/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.logisim.gui.log;

import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitEvent;
import com.cburch.logisim.circuit.CircuitListener;
import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.circuit.Subcircuit;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.data.AttributeEvent;
import com.cburch.logisim.data.AttributeListener;
import com.cburch.logisim.data.Value;

class SelectionItem implements AttributeListener, CircuitListener {
    private Model model;
    private Subcircuit[] path;
    private Component comp;
    private Object option;
    private int radix = 2;
    private String shortDescriptor;
    private String longDescriptor;
    
    public SelectionItem(Model model, Subcircuit[] path, Component comp, Object option) {
        this.model = model;
        this.path = path;
        this.comp = comp;
        this.option = option;
        computeDescriptors();
        
        if(path != null) {
            model.getCircuitState().getCircuit().addCircuitListener(this);
            for(int i = 0; i < path.length; i++) {
                path[i].getAttributeSet().addAttributeListener(this);
                path[i].getSubcircuit().addCircuitListener(this);
            }
        }
        comp.getAttributeSet().addAttributeListener(this);
    }
    
    private boolean computeDescriptors() {
        boolean changed = false;
        
        Loggable log = (Loggable) comp.getFeature(Loggable.class);
        String newShort = log.getLogName(option);
        if(newShort == null || newShort.equals("")) {
            newShort = comp.getFactory().getDisplayName()
                + comp.getLocation().toString();
            if(option != null) {
                newShort += "." + option.toString();
            }
        }
        if(!newShort.equals(shortDescriptor)) {
            changed = true;
            shortDescriptor = newShort;
        }

        StringBuffer buf = new StringBuffer();
        for(int i = 0; i < path.length; i++) {
            if(i > 0) buf.append(".");
            buf.append(path[i].getFactory().getDisplayName());
            buf.append(path[i].getLocation());
            buf.append(".");
        }
        buf.append(shortDescriptor);
        String newLong = buf.toString();
        if(!newLong.equals(longDescriptor)) {
            changed = true;
            longDescriptor = newLong;
        }
        
        return changed;
    }
    
    public Component[] getPath() {
        return path;
    }
    
    public Component getComponent() {
        return comp;
    }
    
    public Object getOption() {
        return option;
    }
    
    public int getRadix() {
        return radix;
    }
    
    public void setRadix(int value) {
        radix = value;
        model.fireSelectionChanged(new ModelEvent());
    }
    
    public String toShortString() {
        return shortDescriptor;
    }
    
    public String toString() {
        return longDescriptor;
    }
    
    public Value fetchValue(CircuitState root) {
        CircuitState cur = root;
        for(int i = 0; i < path.length; i++) {
            cur = path[i].getSubstate(cur);
        }
        Loggable log = (Loggable) comp.getFeature(Loggable.class);
        return log == null ? Value.NIL : log.getLogValue(cur, option);
    }

    public void attributeListChanged(AttributeEvent e) { }

    public void attributeValueChanged(AttributeEvent e) {
        if(computeDescriptors()) {
            model.fireSelectionChanged(new ModelEvent());
        }
    }

    public void circuitChanged(CircuitEvent event) {
        int action = event.getAction();
        if(action == CircuitEvent.ACTION_CLEAR
                || action == CircuitEvent.ACTION_REMOVE) {
            Circuit circ = event.getCircuit();
            Component circComp = null;
            if(circ == model.getCircuitState().getCircuit()) {
                circComp = path != null && path.length > 0 ? path[0] : comp;
            } else if(path != null) {
                for(int i = 0; i < path.length; i++) {
                    if(circ == path[i].getSubcircuit()) {
                        circComp = i + 1 < path.length ? path[i + 1] : comp;
                    }
                }
            }
            if(circComp == null) return;
            
            if(action == CircuitEvent.ACTION_REMOVE
                    && event.getData() != circComp) {
                return;
            }
            
            int index = model.getSelection().indexOf(this);
            if(index < 0) return;
            model.getSelection().remove(index);
        }
    }
}
